<?php

// ------------------------------------------------------------------------
// |@Author       : Jarmin <topextend@qq.com>
// |@----------------------------------------------------------------------
// |@Date         : 2025-05-04 23:29:01
// |@----------------------------------------------------------------------
// |@LastEditTime : 2025-05-09 16:52:48
// |@----------------------------------------------------------------------
// |@LastEditors  : Jarmin <topextend@qq.com>
// |@----------------------------------------------------------------------
// |@Description  :
// |@----------------------------------------------------------------------
// |@FilePath     : Repository.php
// |@----------------------------------------------------------------------
// |@Copyright (c) 2025 http://www.ladmin.cn All Rights Reserved.
// ------------------------------------------------------------------------
declare (strict_types=1);

namespace think\admin;

use think\App;
use think\admin\Model;
use think\admin\traits\CacheTrait;
use think\db\exception\DbException;
use think\admin\exception\DataException;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;

abstract class Repository
{
    /**
     * 缓存特性
     */
    use CacheTrait;

    /**
     * App 实例
     * @var App
     */
    protected App $app;

    /**
     * 主模型实例
     * @var Model
     */
    protected Model $model;

    /**
     * 关联模型实例集合
     * @var array<string, Model>
     */
    protected array $models = [];

    /**
     * 构造方法
     * @param App $app
     */
    public function __construct(App $app)
    {
        $this->app = $app;
        $this->initialize();
    }

    /**
     * 初始化
     */
    abstract protected function initialize(): void;

    /**
     * 获取模型实例
     * @param string|null $name 模型名称，为空则返回主模型
     * @return Model
     * @throws DataException
     */
    protected function getModel(?string $name = null): Model
    {
        if (empty($name)) {
            return $this->model;
        }

        if (!isset($this->models[$name])) {
            throw new DataException("模型 {$name} 未注册");
        }

        return $this->models[$name];
    }

    /**
     * 注册关联模型
     * @param string $name 模型名称
     * @param Model $model 模型实例
     * @return void
     */
    protected function registerModel(string $name, Model $model): void
    {
        $this->models[$name] = $model;
    }

    /**
     * 获取列表
     * @param array $params 查询参数
     * @param string|null $model 模型名称
     * @return array{items: array, total: int, page: int, limit: int}
     * @throws DataException
     */
    public function list(array $params = [], ?string $model = null): array
    {
        // 参数预处理
        $params = array_merge([
            'where' => [],
            'order' => 'id desc',
            'page' => 1,
            'limit' => 15,
            'field' => '*',
            'with' => []
        ], $params);

        $query = $this->getModel($model)
            ->field($params['field'])
            ->where($params['where'])
            ->order($params['order']);

        // 处理关联
        if (!empty($params['with'])) {
            $query = $query->with($params['with']);
        }

        // 获取总数
        $total = $query->count();

        // 获取分页数据
        $items = $query->page($params['page'], $params['limit'])->select();

        return [
            'items' => $items->toArray(),
            'total' => $total,
            'page' => (int)$params['page'],
            'limit' => (int)$params['limit']
        ];
    }

    /**
     * 获取详情
     * @param int $id ID
     * @param array $options 选项 ['field' => '*', 'with' => []]
     * @param string|null $model 模型名称
     * @return array
     * @throws DataException
     */
    protected function detail(int $id, array $options = [], ?string $model = null): array
    {
        if ($id <= 0) {
            throw new DataException('无效的记录ID');
        }

        $query = $this->getModel($model)
            ->field($options['field'] ?? '*')
            ->where('id', $id);

        // 处理关联
        if (!empty($options['with'])) {
            $query = $query->with($options['with']);
        }

        $detail = $query->find();
        if (empty($detail)) {
            throw new DataException('记录不存在');
        }

        return $detail->toArray();
    }

    /**
     * 创建记录
     * @param array $data 数据
     * @param string|null $model 模型名称
     * @return int 创建成功的记录ID
     * @throws DataException
     */
    protected function create(array $data, ?string $model = null): int
    {
        if (empty($data)) {
            throw new DataException('创建数据不能为空');
        }

        $instance = $this->getModel($model);
        if (!$instance->save($data)) {
            throw new DataException('创建失败');
        }

        return $instance->id;
    }

    /**
     * 更新记录
     * @param int $id ID
     * @param array $data 数据
     * @param string|null $model 模型名称
     * @return bool
     * @throws DataException
     */
    protected function update(int $id, array $data, ?string $model = null): bool
    {
        if ($id <= 0) {
            throw new DataException('无效的记录ID');
        }

        if (empty($data)) {
            throw new DataException('更新数据不能为空');
        }

        $instance = $this->getModel($model)->where('id', $id)->find();
        if (empty($instance)) {
            throw new DataException('记录不存在');
        }

        return (bool)$instance->save($data);
    }

    /**
     * 删除记录
     * @param int $id ID
     * @param bool $force 是否强制删除
     * @param string|null $model 模型名称
     * @return bool
     * @throws DataException
     */
    protected function delete(int $id, bool $force = false, ?string $model = null): bool
    {
        if ($id <= 0) {
            throw new DataException('无效的记录ID');
        }

        $instance = $this->getModel($model)->where('id', $id)->find();
        if (empty($instance)) {
            throw new DataException('记录不存在');
        }

        return $force ? (bool)$instance->force()->delete() : (bool)$instance->delete();
    }

    /**
     * 批量删除记录
     * @param array $ids ID数组
     * @param bool $force 是否强制删除
     * @param string|null $model 模型名称
     * @return int 成功删除的记录数
     * @throws DataException
     */
    protected function batchDelete(array $ids, bool $force = false, ?string $model = null): int
    {
        if (empty($ids)) {
            throw new DataException('删除ID不能为空');
        }

        $query = $this->getModel($model)->where('id', 'in', $ids);
        if ($force) {
            $query = $query->force();
        }

        return $query->delete();
    }

    /**
     * 批量更新记录
     * @param array $ids ID数组
     * @param array $data 更新数据
     * @param string|null $model 模型名称
     * @return int 成功更新的记录数
     * @throws DataException
     */
    protected function batchUpdate(array $ids, array $data, ?string $model = null): int
    {
        if (empty($ids)) {
            throw new DataException('更新ID不能为空');
        }

        if (empty($data)) {
            throw new DataException('更新数据不能为空');
        }

        return $this->getModel($model)
            ->where('id', 'in', $ids)
            ->update($data);
    }

    /**
     * 开启事务
     */
    protected function startTrans(): void
    {
        $this->model->startTrans();
    }

    /**
     * 提交事务
     */
    protected function commit(): void
    {
        $this->model->commit();
    }

    /**
     * 回滚事务
     */
    protected function rollback(): void
    {
        $this->model->rollback();
    }
}
